/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.milib.util {
	import flash.utils.Dictionary;

	/**
	 * @author Marek Brun
	 */
	public class MLArrayUtil {
		
		public static function getShuffled(arr:Array):Array {
			var arr2:Array=[];
			arr=arr.concat();
			while(arr.length){
				arr2.push(arr.splice(Math.round(Math.random()*arr.length-1), 1)[0]);
			}
			return arr2;
		}
		
		public static function shuffle(arr:Array):void {
			var copy:Array=arr.concat();
			clear(arr);
			while(copy.length){
				arr.push(copy.splice(Math.floor(Math.random() * arr.length), 1)[0]);
			}
		}
		
		public static function remove(arr:Array, value:*):Boolean {
			var i:uint, isRemove:Boolean;
			while((i=arr.indexOf(value))!=-1){
				isRemove=true;
				arr.splice(i, 1);
			}
			return isRemove;
		}
		
		/*
		 * Moving items in array
		 * ex.
import com.googlecode.milib.util.MLArrayUtil;
var arr:Array=[0,1,2,3,4,5,6,7,8,9];
MLArrayUtil.move(arr, 3); trace(arr); //output:7,8,9,0,1,2,3,4,5,6
MLArrayUtil.move(arr, -3); trace(arr); //output:0,1,2,3,4,5,6,7,8,9
MLArrayUtil.move(arr, -3); trace(arr); //output:3,4,5,6,7,8,9,0,1,2
		 */
		public static function move(arr:Array, positions:int):void {
			if(positions>0){
				positions=positions%arr.length;
				while(positions--){
					arr.unshift(arr.pop());
				}
			}else if(positions<0){
				positions=-positions;
				positions=positions%arr.length;
				while(positions--){
					arr.push(arr.shift());
				}
			}
		}
		
		public static function getArrByObjProp(arr:Array, objectProp:*):Array {
			var i:Number = arr.length;
			var byObj:Array=[];
			while(--i-(-1)){ byObj.push(arr[i][objectProp]); }
			return byObj;
		}
		
		public static function getWhereObjProp(arr:Array, objectPropName:*, value:*):* {
			return arr[getIndexWhereObjProp(arr, objectPropName, value)];
		}
		
		public static function getIndexWhereObjProp(arr:Array, objectPropName:String, value:*):Number {
			var i:Number = arr.length;
			while (--i-(-1)) {
				if(arr[i].hasOwnProperty(objectPropName) && arr[i][objectPropName] == value) {
					return i;
					break;
				}
			}
			return NaN;
		}
		
		public static function getObjWhereObjProp(arr:Array, objectPropName:String, value:*):Number {
			return arr[getIndexWhereObjProp(arr, objectPropName, value)];
		}
		
		public static function getWhereObjsProp(arr:Array, objectPropName:*, value:*):Array {
			var i:Number = arr.length;
			var founds:Array=[];
			while(--i-(-1)) {
				if(arr[i].hasOwnProperty(objectPropName) && arr[i][objectPropName] == value) {
					founds.push(arr[i]);
				}
			}
			return founds;
		}
		
		public static function getWhereObjsPropNot(arr:Array, objectPropName:*, value:*):Array {
			var i:Number = arr.length;
			var founds:Array=[];
			while(--i-(-1)) {
				if(arr[i][objectPropName] != value) {
					founds.push(arr[i]);
				}
			}
			return founds;
		}
		
		public static function getWhereObjsOneOfProps(arr:Array, objectPropName:String, values:Array):Array {
			var i:Number = arr.length;
			var founds:Array=[];
			var p:uint;
			while(--i-(-1)) {
				for(p=0;p<values.length;p++){
					if(arr[i].hasOwnProperty(objectPropName) && arr[i][objectPropName]==values[p]) {
						founds.push(arr[i]);
						break;
					}
				}
			}
			return founds;
		}
		
		public static function getWhereObjsPropNumberBetween(arr:Array, objectPropName:String, betweenIni:Number, betweenEnd:Number):Array {
			var i:Number = arr.length;
			var founds:Array=[];
			while(--i-(-1)) {
				if(arr[i].hasOwnProperty(objectPropName) && arr[i][objectPropName] >= betweenIni && arr[i][objectPropName] <= betweenEnd) {
					founds.push(arr[i]);
				}
			}
			return founds;
		}
		
		public static function getByProp(arr:Array, propNumOrName:Object):Array {
			var byProp:Array=[];
			for(var i:uint=0;i<arr.length;i++){
				byProp[arr[i][propNumOrName]]=arr[i];
			}
			return byProp; 
		}
		
		/**
		 * @param arr Array or Vector
		 */
		public static function getNextByValue(arr:*, value:*):* {
			var valueIndex:uint=arr.indexOf(value);
			if(valueIndex==arr.length-1){
				return arr[0];
			}
			return arr[valueIndex+1];
		}
		
		/**
		 * @param arr Array or Vector
		 */
		public static function getPrevByValue(arr:*, value:*):* {
			var valueIndex:uint=arr.indexOf(value);
			if(valueIndex==0){
				return arr[arr.length-1];
			}
			return arr[valueIndex-1];
		}
		
		public static function getByTurn(arr:Array, value:*, turn:Number):Object {
			if(turn>0){ return getNextByValue(arr, value); }
			else{ return getPrevByValue(arr, value); }
		}
		
		public static function got(arr:Array, value:*):Boolean {
			return arr.indexOf(value)!=-1;
		}
		
		public static function gotObjVar(arr:Array, varName:String, value:*):Boolean {
			for(var i:uint=0;i<arr.length;i++){
				if(arr[i][varName]===value){ return true; }
			}
			return false;
		}
		
		public static function addUnique(arr:Array, value:*):Boolean {
			if(arr.indexOf(value)==-1){
				arr.push(value);
				return true;
			}
			return false;
		}
		
		public static function removeValues(arr:Array, toRemoves:Array):void {
			for(var i:uint=0;i<toRemoves.length;i++){ remove(arr, toRemoves[i]); }
		}
		
		public static function getRotated2D(array2D:Array):Array {
			var longestRow:Number=0;
			var iX:uint, iY:uint;
			for(iX=0;iX<array2D.length;iX++){
				if(array2D[iX].length>longestRow){
					longestRow=array2D[iX].length;
				}
			}
			
			var rMatrix:Array=[];
			for(iX=0;iX<array2D.length;iX++){
				for(iY=0;iY<longestRow;iY++){
					if(!rMatrix[iY]){ rMatrix[iY]=[]; }
					rMatrix[iY][iX]=array2D[iX][iY];
				}
			}
			
			return rMatrix;
		}
		
		public static function applyProps(arr:Array, propName:String, value:*):void {
			var len:uint=arr.length;
			for(var i:uint=0;i<len;i++){
				arr[i][propName]=value;
			}
		}
		
		public static function clear(arr:Array):void {
			var i:Number = arr.length;
			while(--i-(-1)){ arr.splice(i, 1); }
		}
		
		public static function divideToParts(arr:Array, parts:Number):Array {
			var partsArr:Array=[];
			arr=arr.concat();
			var partLength:Number=int(arr.length/parts);
			for(var i:uint=0;i<parts;i++){
				partsArr.push(
					arr.splice(0, partLength)
				);
			}
			
			return partsArr;
		}
		
		public static function getRandom(arr:Array):* {
			return arr[Math.round(Math.random()*(arr.length-1))];
		}
		
		public static function pushAfter(arr:Array, inArrBefore:*, toPushAfter:*):void {
			if(!got(arr, inArrBefore)){ return; }
			var inArrIndex:uint=arr.indexOf(inArrBefore);
			if(inArrIndex==arr.length-1){
				arr.push(toPushAfter);
			}else{
				var restArr:Array=arr.splice(inArrIndex+1);
				arr.push(toPushAfter);
				arr.push.apply(arr, restArr);
			}
		}
		
		public static function pushBefore(arr:Array, inArrAfter:*, toPushBefore:*):void {
			if(!got(arr, inArrAfter)){ return; }
			var inArrIndex:uint=arr.indexOf(inArrAfter);
			if(inArrIndex==0){
				arr.unshift(toPushBefore);
			}else{
				var restArr:Array=arr.splice(inArrIndex);
				arr.push(toPushBefore);
				arr.push.apply(arr, restArr);
			}
		}
		
		public static function getArrayByDictionary(dict:Dictionary):Array {
			var arr:Array=[];
			for(var n:* in dict){
				arr.push(dict[n]);
			}
			return arr;
		}
	}
}
